/*
 * Mmap.cpp
 *
 *  Created on: Nov 5, 2013
 *      Author: vladimir
 */

#include "Mmap.hpp"

#include "AccessType.hpp"
#include "ErrorSystemCall.hpp"

#include <utility>
#include <cerrno>
#include <sys/mman.h>

namespace vjipc
{

namespace
{

void* CallMmap( const size_t length,
                const int prot,
                const int fd )
{
	void* address = mmap( NULL, length, prot, MAP_SHARED, fd, 0 );

	if ( MAP_FAILED == address )
	{
		const std::string errMsg( "Error mmap()-ing a memory region." );
		throw btexc::ErrorSystemCall( errMsg, errno );
	}

	return address;
}

void* MmapTheFileIntoMemory( const vjipc::AccessType & accessType,
                             const unsigned int length,
                             const int fd )
{
	void* address = 0;
	switch ( accessType )
	{
		case vjipc::AccessType::READ_ONLY :
			address = CallMmap( length, PROT_READ, fd );
			break;

		case vjipc::AccessType::READ_WRITE :
			address = CallMmap( length, PROT_WRITE | PROT_READ, fd );
			break;

		default :
			throw btexc::ErrorBase( "Unsupported type " + std::to_string( static_cast<int>( accessType ) ) );
	}

	return address;
}

}

Mmap::Mmap( const vjipc::AccessType & accessType,
            const int fd,
            const unsigned int length_ ) :
		length( length_ ),
		address( MmapTheFileIntoMemory( accessType, length_, fd ) )
{
}

Mmap::~Mmap()
{
	if ( 0 != length )
	{
		munmap( address, length );
	}
}

Mmap::Mmap( Mmap&& rhs ) :
				length( std::move( rhs.length ) ),
				address( std::move( rhs.address ) )
{
}

Mmap& Mmap::operator =( Mmap&& rhs )
{
	length = std::move( rhs.length );
	address = std::move( rhs.address );

	rhs.length = 0;
	rhs.address = nullptr;

	return *this;
}

void* Mmap::GetAddressToMmappedRegion() const
{
	return address;
}

} /* namespace vjipc */
